package models

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"strconv"
	"sync"

	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
	"gorm.io/gorm"
)

// go get gopkg.in/fatih/set.v0

// Message 消息信息
type Message struct {
	gorm.Model
	FromID  uint   // 发送者id
	ToID    uint   // 接收者id
	Type    uint   // 消息关系 私聊 群聊 广播
	Media   uint   // 消息类型 文字 图片 音频
	Content string // 消息内容
	Pic     string
	URL     string
	Desc    string
	Amount  int
}

// TableName 表名
func (*Message) TableName() string {
	return "message"
}

// Node 节点
type Node struct {
	Conn      *websocket.Conn
	DataQueue chan []byte
	GroupSets set.Interface
}

var clientMap = make(map[uint]*Node, 0)
var rwLocker sync.RWMutex
var udpSendChan = make(chan []byte, 1024)

// Chat 聊天
func Chat(writer http.ResponseWriter, request *http.Request) {
	// 1. 获取参数,校验token
	query := request.URL.Query()
	userID, _ := strconv.ParseUint(query.Get("userId"), 10, 32)
	// token := query.Get("token")
	// toID, _ := strconv.ParseUint(query.Get("toId"), 10, 64)
	// msgType := query.Get("msgType")
	// content := query.Get("content")
	// 2. 获取连接
	ws, err := (&websocket.Upgrader{
		CheckOrigin: func(req *http.Request) bool {
			return true
		},
	}).Upgrade(writer, request, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	node := &Node{
		Conn:      ws,
		DataQueue: make(chan []byte, 0),
		GroupSets: set.New(set.ThreadSafe),
	}

	// 3. 用户关系

	// 4. 关系映射
	rwLocker.Lock()
	clientMap[uint(userID)] = node
	rwLocker.Unlock()

	// 5. 发送消息
	go func(node *Node) {
		for {
			select {
			case data := <-node.DataQueue:
				fmt.Printf("[Send]%v: %v\n", node, data)
				err := node.Conn.WriteMessage(websocket.TextMessage, data)
				if err != nil {
					fmt.Println(err)
					return
				}
			}
		}
	}(node)
	// 6. 接收消息
	go func(node *Node) {
		for {
			_, data, err := node.Conn.ReadMessage()
			fmt.Printf("[Recv]%v: %v\n", node, data)
			if err != nil {
				fmt.Println(err)
				return
			}
			udpSendChan <- data
			fmt.Println("[ws] <<< ", data)
		}
	}(node)
	SendMsg(uint(userID), []byte("欢迎进入聊天系统...."))
}

func init() {
	fmt.Println("启动initUDP....")
	// 发送udp消息
	go func() {
		fmt.Println("启动UDP发送....")
		conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
			IP:   net.IPv4(192, 168, 10, 255),
			Port: 3000,
		})
		if err != nil {
			fmt.Println(err)
			return
		}
		defer conn.Close()

		for {
			select {
			case data := <-udpSendChan:
				fmt.Printf("[SendUDPMsg]: %v\n", data)
				_, err := conn.Write(data)
				if err != nil {
					fmt.Println(err)
					return
				}
			}
		}
	}()
	// 接收udp消息
	go func() {
		fmt.Println("启动UDP接收....")
		conn, err := net.ListenUDP("udp", &net.UDPAddr{
			IP:   net.IPv4zero,
			Port: 3000,
		})
		if err != nil {
			fmt.Println(err)
			return
		}
		defer conn.Close()
		for {
			var buf [512]byte
			n, err := conn.Read(buf[0:])
			if err != nil {
				fmt.Println(err)
				return
			}
			msg := &Message{}
			err = json.Unmarshal(buf[:n], &msg)
			if err != nil {
				fmt.Println(err)
				return
			}
			fmt.Printf("[RecvUDPMsg]->%d: %v\n", msg.ToID, buf[0:])
			switch msg.Type {
			// 私聊
			case 1:
				SendMsg(msg.ToID, buf[0:])
			// 群聊
			case 2:

			// 广播
			case 3:

			case 4:

			}
		}
	}()
}

// SendMsg 发送消息
func SendMsg(toID uint, data []byte) {
	rwLocker.RLock()
	node, ok := clientMap[toID]
	rwLocker.RUnlock()
	if ok {
		fmt.Printf("[SendMsg]->%d: %v\n", toID, data)
		node.DataQueue <- data
	}
}
